﻿using CRL.Core;
using CRL.RedisProvider;
using System;
using System.Linq;
using System.Collections.Generic;

using System.Collections;
using CRL.Transaction;
using CRL.Transaction.Test;
using CRL.DBAccess;
using CRL;
using CRL.Sqlite;
using CRL.Core.Extension;
using System.Xml.Linq;
using ConsoleTables;

namespace transTest
{
    class Program
    {
        static TccControl tccControl;
        static SagaControl sagaControl;
        const string sqlLiteDb = "Data Source=d:\\sqlliteTest.db;";
        static Dictionary<string, Dictionary<string, bool>> setpsState = new Dictionary<string, Dictionary<string, bool>>();
        static Dictionary<string, string> resultState = new Dictionary<string, string>();

        static bool useDelegate = false;
        static void Main(string[] args)
        {
            var builder = DBConfigRegister.GetInstance();
            builder.UseSqlite();
            builder.RegisterDBAccessBuild(dbLocation =>
            {
                return new DBAccessBuild(DBType.SQLITE, sqlLiteDb);
            });
            var cb = new ConfigBuilder();
            cb.UseRedis("Server_204@127.0.0.1:6389");

            //TransConfig.RegisterTransInfoManage("test", () => new TransInfoManage());
            TransConfig.RegisterTransInfoManage("test", () => new TransInfoManageRedis());
            setpsState.Add("try",new Dictionary<string, bool>());
            setpsState.Add("commit", new Dictionary<string, bool>());
            setpsState.Add("cancel", new Dictionary<string, bool>());

            initControl();
            ConsoleTest.DoCommand(typeof(Program));
        }
        static void initTcc()
        {
            clearStatus();
            tccControl = new TccControl();
            tccControl.Start(new TransOptions { Name = "testTcc", MaxRetryCount = 1, RetryInterval = TimeSpan.FromSeconds(1), Args = DateTime.Now, UseLog = true, CheckKey = Guid.NewGuid().ToString() });
            if (!useDelegate)
            {
                tccControl.Then<TccStep1>().Then<TccStep2>().Then<TccStep3>();
            }
            else
            {
                tccControl.Then(() =>
                {
                    print("tcc", "try", 1);
                }, () =>
                {
                    print("tcc", "commit", 1);
                }, () =>
                {
                    print("tcc", "cancel", 1);
                }).Then(() =>
                {
                    print("tcc", "try", 2);
                }, () =>
                {
                    print("tcc", "commit", 2);
                }, () =>
                {
                    print("tcc", "cancel", 2);
                }).Then(() =>
                {
                    print("tcc", "try", 3);
                }, () =>
                {
                    print("tcc", "commit", 3);
                }, () =>
                {
                    print("tcc", "cancel", 3);
                });
            }
        }
        static void initSaga()
        {
            clearStatus();
            sagaControl = new SagaControl();
            sagaControl.Start(new TransOptions { Name = "testSaga", MaxRetryCount = 1, RetryInterval = TimeSpan.FromSeconds(1), Args = DateTime.Now, UseLog = true, CheckKey = Guid.NewGuid().ToString() });
            if (!useDelegate)
            {
                sagaControl.Then<SagaStep1>().Then<SagaStep2>().Then<SagaStep3>();
            }
            else
            {
                sagaControl.Then(() =>
                {
                    print("saga", "commit", 1);
                }, () =>
                {
                    print("saga", "cancel", 1);
                }).Then(() =>
                {
                    print("saga", "commit", 2);
                }, () =>
                {
                    print("saga", "cancel", 2);
                }).Then(() =>
                {
                    print("saga", "commit", 3);
                }, () =>
                {
                    print("saga", "cancel", 3);
                });
            }
        }
        public static void initControl()
        {
            Console.WriteLine($"使用 {(useDelegate ? "内存" : "数据库")}");
            initTcc();
            initSaga();
            resultState.Clear();
            for (var i = 1; i < 4; i++)
            {
                resultState.Add($"tcc_{i}", "pengding");
                resultState.Add($"saga_{i}", "pengding");
            }
        }
        internal static void print(string name, string type, int index)
        {
            var dic = setpsState[type];
            if (dic.ContainsKey($"{name}{index}"))
            {
                throw new Exception("fail");
            }
            resultState[$"{name}_{index}"] += $" {type}";
            Console.WriteLine($"step{index} {type}");
        }
        static void checkResult(string name, int index, string should)
        {
            var v = resultState[$"{name}_{index}"];
            Console.WriteLine($"check step{index} [{v.Trim()}]==[{should.Trim()}] {v.Trim() == should.Trim()}");
        }
        static void clearStatus()
        {
            setpsState["try"].Clear();
            setpsState["commit"].Clear();
            setpsState["cancel"].Clear();
        }
        static void setErrorState(string name, string type, int index)
        {
            var dic = setpsState[type];
            dic[$"{name}{index}"] = true;
        }
        #region tcc
        public static void testTccCommit()
        {
            //成功
            clearStatus();
            var result = tccControl.Execute();
    
            //Console.WriteLine($"testTcc 执行 {result.ToJson()}");
            checkResult("tcc", 1, "pengding try commit");
            checkResult("tcc", 2, "pengding try commit");
            checkResult("tcc", 3, "pengding try commit");
            ConsoleTable.Display(result);
        }
        public static void testTccCommitError()
        {
            //提交失败需要重试
            clearStatus();
            setErrorState("tcc", "commit", 2);
            var result = tccControl.Execute();
            //Console.WriteLine($"testTcc 执行 {result.ToJson()}");
            checkResult("tcc", 1, "pengding try commit");
            checkResult("tcc", 2, "pengding try ");
            checkResult("tcc", 3, "pengding try commit");
            ConsoleTable.Display(result);
        }
        public static void testTccTryCancel()
        {
            //失败后取消
            clearStatus();
            //setErrorState("tcc", "cancel", 1);
            setErrorState("tcc", "try", 2);
            var result = tccControl.Execute();
            //Console.WriteLine($"testTcc 执行 {result.ToJson()}");
            checkResult("tcc", 1, "pengding try cancel");
            checkResult("tcc", 2, "pengding");
            checkResult("tcc", 3, "pengding");
            ConsoleTable.Display(result);
        }
        public static void testTccCancelError()
        {
            //取消失败需要重试
            clearStatus();
            setErrorState("tcc", "cancel", 1);
            setErrorState("tcc", "try", 2);
            var result = tccControl.Execute();
            //Console.WriteLine($"testTcc 执行 {result.ToJson()}");
            checkResult("tcc", 1, "pengding try");
            checkResult("tcc", 2, "pengding");
            checkResult("tcc", 3, "pengding");
            ConsoleTable.Display(result);
        }
        #endregion
        #region saga
        public static void testSagaCommit()
        {
            clearStatus();
            var result = sagaControl.Execute();
            //Console.WriteLine($"testSaga 执行 {result.ToJson()}");
            checkResult("saga", 1, "pengding commit");
            checkResult("saga", 2, "pengding commit");
            checkResult("saga", 3, "pengding commit");
            ConsoleTable.Display(result);
        }
        public static void testSagaCancel()
        {
            //提交失败取消成功
            clearStatus();
            setErrorState("saga", "commit", 3);
            var result = sagaControl.Execute();
            //Console.WriteLine($"testSaga 执行 {result.ToJson()}");
            checkResult("saga", 1, "pengding commit cancel");
            checkResult("saga", 2, "pengding commit cancel");
            checkResult("saga", 3, "pengding");
            ConsoleTable.Display(result);
        }
        public static void testSagaCancelError()
        {
            //取消失败需要重试
            clearStatus();
            setErrorState("saga", "commit", 3);
            setErrorState("saga", "cancel", 1);
            var result = sagaControl.Execute();
            //Console.WriteLine($"testSaga 执行 {result.ToJson()}");
            checkResult("saga", 1, "pengding commit");
            checkResult("saga", 2, "pengding commit cancel");
            checkResult("saga", 3, "pengding");
            ConsoleTable.Display(result);
        }
        #endregion
        public static void testNoTry()
        {
            var tccControl2 = new TccControl();
            tccControl2.Start(new TransOptions { Name = "testTcc", MaxRetryCount = 1, RetryInterval = TimeSpan.FromSeconds(1), Args = DateTime.Now, UseLog = true });
            tccControl2.Then<TccStepNoTry>("2222");
            tccControl2.Execute();
        }
    }

}
